package parser;

import java.io.PrintWriter;
import codeGeneration.OperatorConverter;
import lexer.*;

/**
 * Parses and stores Binary Expressions into an appropriate format Grammar:
 * (expr) (operator) (expr)
 */
public class LogoBinaryExpression extends LogoExpression {

	LogoExpression leftExpression;
	LogoExpression rightExpression;
	TokenType operator;

	/**
	 * Parse a BinaryExpression from the current TokenIterator
	 * 
	 * @param TokenIterator
	 * @throws LogoParseException
	 */
	public LogoBinaryExpression(TokenIterator it) throws LogoParseException {
		if (!it.hasNext()) {
			throw new LogoParseException("Unexpectedly reached end of program");
		}
		Token highestPrecedence = null;
		int highestPrecedenceIndex = -1;

		// Store where we were at the start of the binary expression parse so we
		// know
		// where the beginning of the left expression was
		int pos = it.getIndex();
		while (it.hasNext() && (it.matchNextTokenAndOperator(TokenType.IDENTIFIER) || it.matchNextTokenAndOperator(TokenType.NUMBER))) {
			it.next();
			if (LogoPrecedence.getPrecendence(it.peek()) > LogoPrecedence.getPrecendence(highestPrecedence)) {
				highestPrecedenceIndex = it.getIndex();
				highestPrecedence = it.next();
			} else {
				it.next();
			}
		}
		it.pos = pos;

		if (highestPrecedence != null) {
			leftExpression = LogoExpressionParser.parseExpression(it.split(it.peek(), highestPrecedence));
			it.pos = highestPrecedenceIndex + 1;
			rightExpression = LogoExpressionParser.parseExpression(it);
			operator = highestPrecedence.getType();
		} else {
			throw new LogoParseSyntaxException(it.peek(), "Binary Expression. (expr) (operator) (expr)");
		}
	}

	@Override
	public void resolveIdentifiers(LogoScope scope) throws LogoParseException {
		leftExpression.resolveIdentifiers(scope);
		rightExpression.resolveIdentifiers(scope);
	}

	/**
	 * Example Output: "5 2 sub" or "2 1 add 2 sub"
	 */
	@Override
	public void generatePostScriptCode(PrintWriter stream) {
		leftExpression.generatePostScriptCode(stream);
		rightExpression.generatePostScriptCode(stream);
		stream.println(OperatorConverter.getOperator(operator));
	}

}
